#!/usr/bin/python
# -*- coding : utf-8 -*-
# Filename : analysisIni.py

import sys
import re

class Ini(object):
    '''Analysis ini files'''

    sectionDic = {}
    currentDic = {}
    lineNo = 0
    errorNo = "Normal"
    errorDic = { 
            "NotCloseBracket" : "Not closed square brackets",
            "CantOpenFile" : "Can't open file",
            "CantReadFile" : "Can't read from file",
            "Empty" : "Section or Ident is empty",
            "OtherLetters" : "Other letters following Section",
            "NoneSection" : "Ident belongs to none Section",
            "SyntaxError" : "Section or Ident have Syntax Error"
    }
    invalidChReg = "(\*|\?|\[|\]|\(|\)|=|:)"
            

    def __init__( self ):
        self.regObj = re.compile(self.invalidChReg)
        self.quotationGetReg = re.compile("^('|\")(.*)\\1$")
        self.quotationFindReg = re.compile(".*(\"|').*")

    def parse( self, filename ):
        '''Parse files and save into Dictionarys'''

        try:
            file = open( filename, "r" )
        except IOError:
            self.errorNo = "CantOpenFile" 
            return False
        else:
            try:
                for line in file:
                    self.lineNo += 1
                    if not self.__parseLine( line.strip() ):
                        return False
            except IOError:
                self.errorNo = "CantReadFile"
                return False

        return True

    def read_string( self, section, ident, default=None ):
        '''Interface to read special ident'''
        sec = self.sectionDic.get( section, None )

        if sec is None:
            return default
        else:
            return sec.get( ident, default );

    def reportError( self ):
        '''Return the Error information with line number'''
        return "".join( ("Parse file error:\nline ", str(self.lineNo), 
            ":  ", self.errorDic[self.errorNo]) )

    def __checkKeyword( self, keyword, canNone=False ):
        '''Judge whether the keyword is valid'''
        if not len( keyword[0] ) and not canNone:
            return "Empty"

        if self.regObj.search( keyword[0] ):
            return "SyntaxError"

        #We must have quotes around the keyword not a single
        if self.quotationFindReg.search( keyword[0] ):
            match = self.quotationGetReg.search( keyword[0] )
            if match:
                keyword[0] = match.group(2)
            else:
                return "SyntaxError"

        return "Normal"

    def __parseBracket( self, line ):
        '''Parse section line'''
        findEnd = "NotCloseBracket"
        for index, character in enumerate( line[1:] ):
            if character == ']':
                self.currentSection = line[1:index+1].strip()
                tempList = [ self.currentSection ]
                findEnd = self.__checkKeyword( tempList )
                
                if findEnd == "Normal":
                    self.currentSection = tempList[0]
                    continue
                else:
                    break

                if findEnd == "Normal":
                    findEnd = "OtherLetters"
                    break

            if character == ';':
                break

        if findEnd != "Normal":
            self.errorNo = findEnd 
            return False
        else:
            if self.sectionDic.get( self.currentSection ) is None and findEnd == "Normal":
                subDic = {}
                self.currentDic = subDic
                self.sectionDic[self.currentSection] = subDic

        return True

    def __addIdent( self, key, value ):
        '''Check whether can add Ident'''
        if len( self.sectionDic ):
            tempList = [ key.strip() ]
            errorNo = self.__checkKeyword( tempList )
            if errorNo != "Normal":
                self.errorNo = errorNo 
                return False
            key = tempList[0]
                    
            tempList = [ value.strip() ]
            errorNo = self.__checkKeyword( tempList, True )
            if errorNo != "Normal":
                self.errorNo = errorNo 
                return False        
            value = tempList[0]

            self.currentDic[ key ] = value
        else:
            self.errorNo = "NoneSection" 
            return False

        return True

    def __parseIdent( self, line ):
        '''Parse ident line'''
        equalPosition = -1
        key = ''
        value = ''
        for index, character in enumerate( line[1:]+';' ):
            if character == '=':
                key = line[0:index+1].strip()
                equalPosition = index
            elif character == ';':
                value = line[equalPosition+2:index+1]
                return self.__addIdent( key, value )

    def __parseLine( self, line ):
        '''Private function to parse each Line'''

        if not len( line ):
            return True

        if line[0] == ';':
            return True

        if line[0] == '[':
            return self.__parseBracket( line )
        else:
            return self.__parseIdent( line )

    def __showAll( self ):
        '''Private function for test'''

        for key, value in self.sectionDic.iteritems():
            print '['+key+']'
            for subKey, subValue in value.iteritems():
                print subKey+'='+subValue


def main( filename ):
    myIni = Ini()
    if myIni.parse( filename ) == False:
        print myIni.reportError()
        return

    x = myIni.read_string( 'Mail', 'MAPI', 'jfkdj');
    print x
    myIni._Ini__showAll()

if __name__ == '__main__':
    ''' A test program list the all idents in file filename'''

    if( len( sys.argv ) != 2):
        print 'Usage: analysisIni.py filename'
        sys.exit()

    filename = sys.argv[1]
    main( filename )

# End of CIni.py

